package com.server.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.entity.TeacherTable;
import com.entity.TeacherTableDto;
import com.mapper.db2.TeacherTableMapper;
import com.server.ITeacherTableService;
import com.util.BeanUtils;
import com.util.ColltionUtils;
import com.util.Response;
import com.util.thread.ThreadPoolUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author chl
 * @since 2022-03-22
 */
@Service
@Slf4j
public class TeacherTableServiceImpl extends ServiceImpl<TeacherTableMapper, TeacherTable> implements ITeacherTableService {

    @Autowired
    private TeacherTableMapper teacherTableMapper;

    @Override
    public List<TeacherTable> selectList(TeacherTable teacherTable) {


        Map map = new HashMap<>();
        map.put("teacher_name", "我的xiaoxiao");
        map.put("teacher_no", null);


        // 传递式访问接口
        LambdaQueryChainWrapper<TeacherTable> lambdaQueryChainWrapper = new LambdaQueryChainWrapper(teacherTableMapper);
        Integer count = lambdaQueryChainWrapper.count();
        List<TeacherTable> warpper = lambdaQueryChainWrapper.like(TeacherTable::getTeacherName, "张老师").list();



        LambdaQueryWrapper<TeacherTable> queryWrapper = new LambdaQueryWrapper<>();


        // 1.可作为关联小表查询
        // 执行语句 SELECT id,teacher_name,teacher_no,teacher_address FROM teacher_table
        // WHERE (id IN (select id from teacher_table where teacher_address >15 ))
//        queryWrapper.inSql(TeacherTable::getId, "select id from teacher_table where teacher_address >15 ");


        // 2. 分组  排序  补充条件
//         queryWrapper.groupBy(true, TeacherTable::getTeacherNo)
//                     .orderByAsc(TeacherTable::getTeacherAddress)
//                      .having("teacher_address > 15")

        // 3.or的用法
        // 执行语句 select * from table address = 18 or address = 19
//                .eq(TeacherTable::getTeacherAddress, 18)
//                .or()
//                .eq(TeacherTable::getTeacherAddress, 19)

        // 4.多条件判断, 可括号嵌套包裹
        // 执行语句 SELECT id,teacher_name,teacher_no,teacher_address,create_time FROM teacher_table
        // WHERE ((teacher_name = ? OR teacher_address <> ?) AND (teacher_name = ? OR teacher_address <> ?))
//        queryWrapper.eq(TeacherTable::getId, 1)
//                .and(true, t -> {
//                    t.eq(TeacherTable::getTeacherName, "我的xiaoxiao")
//                            .or().ne(true, TeacherTable::getTeacherAddress, 18);
//                }).and(a -> {
//            a.eq(TeacherTable::getTeacherName, "xiaoxiao")
//                    .or().ne(true, TeacherTable::getTeacherAddress, 19);
//        });

        // 5.nested  增加了括号（）隔离SQL，可做不同条件使用，跟示例4用法类似
        // SELECT * FROM teacher_table WHERE ((teacher_address = ? OR teacher_name = ?) AND (teacher_address <> ? OR teacher_name = ?))
//        queryWrapper
//                .nested(true, t -> t.eq(TeacherTable::getTeacherAddress, 18)
//                        .or().eq(TeacherTable::getTeacherName, "张三")
//                )
//                .nested(t -> t.ne(TeacherTable::getTeacherAddress, 19)
//                        .or().eq(TeacherTable::getTeacherName, "李四")
//                );


        // 6.sql拼接，sql函数用此语法
//        queryWrapper.apply("date_format('20080808','%Y-%m-%d') < create_time ");


        // 7.last，只能用一次，以最后一次为准，有sql注入风险
//        queryWrapper.last("limit 1");

        // 8.返回布尔值，true或false，为真则执行，为假则返回空集。notExists则与exists相反
//        queryWrapper.exists("select id from teacher_table where id = '222' ");


        List<TeacherTable> list = list(queryWrapper);
        // 手动分页,见集合文件夹下lambda
        List<TeacherTable> collect = list.stream().skip(2).limit(2).collect(Collectors.toList());


        //  mapper注解的用法
        TeacherTable table = new TeacherTable();
        table.setId(Long.valueOf("222"));
        List<TeacherTable> tableList = teacherTableMapper.getList(table);


        // wrapper的用法查询，key是数据库映射的字段，省去xml
        List<TeacherTable> tableList2 = teacherTableMapper.getAll(new QueryWrapper<TeacherTable>()
                .eq("id", table.getId())
                .or()
                .eq("teacher_address", 18));
        return null;
    }


    // 事务回滚验证
    @Override
    @Transactional(value = "test2TransactionManager")
    public Response add(TeacherTable node) {
        node.setTeacherAddress("老师地址");
        node.setTeacherName("涨老师");
        node.setTeacherNo("1000001");
        node.setCreateTime(new Date());
//        node.setId(Long.valueOf("222"));

//        boolean b = updateById(node);
        boolean save = save(node);
//        System.out.println(" 是否成功:" + save);

        return save ? Response.createSuccess("成功") : Response.createError("成功");

    }

    @Override
    public List<Long> batchAdd(TeacherTable teacherTable) {
        TeacherTable node = new TeacherTable();
//        node.setTeacherAddress("测试老师地址4");
        node.setTeacherName("张老师");
        node.setTeacherNo("003");
        node.setCreateTime(new Date());
        TeacherTable node1 = new TeacherTable();
//        node1.setTeacherAddress("测试老师地址5");
        node1.setTeacherName("李老师");
        node1.setTeacherNo("004");
        node1.setCreateTime(new Date());

        List<TeacherTable> list = new ArrayList<>();
        list.add(node);
        list.add(node1);
        List<Long> longs = null;
        int i = teacherTableMapper.batchAdd(list);
        System.out.println(" :" + i);

        return longs;

    }




    @Override
    public String multithreadingAdd() {
        long l = System.currentTimeMillis();
        batchAdd();
        long l1 = (System.currentTimeMillis() - l);
        log.info("耗时：{}毫秒", l1);
        return String.valueOf(l1);
    }

  // 分页条件查询，每次查询数据数量
  private static final Integer NUMBER = 10;


    @Override
    public List<TeacherTable> multithreadingSelect() {

        System.out.println("开始执行多线程...");
        long startTime = System.currentTimeMillis();
        // 要查询数据的总数
        int count = count();
        // 循环查询次数
        int cishu = 100 / NUMBER;
        List<TeacherTableDto> list = new CopyOnWriteArrayList<>();

        /**
         * ### 如果线程数（ExecutorService）少于要循环的次数，会出现线程等待；如果（CountDownLatch）计算少于循环次数，则达到次数就会停止线程，导致缺少数据
         *     计数器的使用，每次循环计数器减一，为零的时候计数器会释放所有线程，不然的话所有线程一直处于被占用状态下，数据也无法返回
         */
//        ExecutorService executorService = Executors.newFixedThreadPool(cishu);

        ThreadPoolUtils threadPoolUtils = ThreadPoolUtils.getInstance();
        CountDownLatch countDownLatch = new CountDownLatch(cishu);
        int pageNumber = 0;
        for (int i = 1; i <= cishu; i++) {
            int pageNum = pageNumber ;

            threadPoolUtils.executor(()->{
                List<TeacherTableDto> teacherTables = teacherTableMapper.getPageList(pageNum, NUMBER);
                list.addAll(teacherTables);
                System.out.println("当前线程name : " + Thread.currentThread().getName());
                countDownLatch.countDown();

            });
            /*Runnable runnable = new Runnable() {
                @Override
                public void run() {

                    try {
                        Thread.sleep(3000);
                        List<TeacherTable> teacherTables = teacherTableMapper.getPageList(pageNum, NUMBER);
                        list.addAll(teacherTables);
                        System.out.println("当前线程name : " + Thread.currentThread().getName());
                        countDownLatch.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            };
            executorService.execute(runnable);*/
            pageNumber += NUMBER;
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("submit总共cost 时间：" + (System.currentTimeMillis()-startTime)/1000 + "秒");
        threadPoolUtils.shutdown();
        System.out.println("查询总条数" + list.size());

        List<TeacherTable> teacherTables = BeanUtils.collectionCopy(list, TeacherTable.class);
        return teacherTables;
        /*int pageNumber = 0;
        int pageSize = 0;
        while (true){
            pageSize += 1000;
            dataMigrateExecutor.execute(() -> {
                List<TeacherTable> teacherTables = list(new LambdaQueryWrapper<TeacherTable>().last("limit ${pageNumber} ${pageSize}"));
                list.addAll(teacherTables);
            });
            pageNumber += 10000;
        }*/

    }

    @Override
    public List<TeacherTable> multithreadingSelect2() {

        System.out.println("开始执行多线程...");
        long startTime = System.currentTimeMillis();
        // 表里总数
//        int count = count();
        int count = 100;

        // 循环次数
        int cishu = count / NUMBER;

        List<TeacherTable> list = new CopyOnWriteArrayList<>(); // 接收返回总集合


//        ExecutorService executorService = Executors.newFixedThreadPool(cishu);
        ThreadPoolUtils threadPoolUtils = ThreadPoolUtils.getInstance();
        CountDownLatch countDownLatch = new CountDownLatch(cishu);
        int pageNumber = 0;
        int pageSize = NUMBER; // 每次查询的条数

        for (int i = 1; i <= cishu; i++) {
            String limit = "limit " + pageNumber + "," + pageSize;
            String index = i + "";
            int pageNum = pageNumber ;
            threadPoolUtils.executor(()->{
                /*try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
                System.out.println(String.format("第%s次", (index)) + limit);
                List<TeacherTable> teacherTables = list(new LambdaQueryWrapper<TeacherTable>().last(limit));
//                List<TeacherTable> teacherTables = teacherTableMapper.getPageList(pageNum, NUMBER);
                list.addAll(teacherTables);
                System.out.println("当前线程name : " + Thread.currentThread().getName());
                countDownLatch.countDown();

            });

            pageNumber += NUMBER;
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("submit总共cost 时间：" + (System.currentTimeMillis()-startTime)/1000 + "秒");
        threadPoolUtils.shutdown();
        System.out.println("查询总条数:" + list.size());
        return list;
        /*int pageNumber = 0;
        int pageSize = 0;
        while (true){
            pageSize += 1000;
            dataMigrateExecutor.execute(() -> {
                List<TeacherTable> teacherTables = list(new LambdaQueryWrapper<TeacherTable>().last("limit ${pageNumber} ${pageSize}"));
                list.addAll(teacherTables);
            });
            pageNumber += 10000;
        }*/

    }

    @Override
    public List<TeacherTable> multithreadingSelect3() {
        int count = 100;

        // 循环次数
        int cishu = count / NUMBER;

        List<TeacherTable> list = new CopyOnWriteArrayList<>(); // 接收返回总集合

        //Callable用于产生结果
        List<Callable<List>> tasks = new ArrayList<>();
        int pageNumber = 0;
        for (int i = 1; i <= cishu; i++) {
            int startNum = pageNumber; // 对应的数据要和i挂钩 ，否则数据不变
            int endNum =i;
            Callable<List> qfe = new TeacherTableDto(startNum, NUMBER);
            tasks.add(qfe);
            pageNumber += NUMBER;
        }
        try{
            //定义固定长度的线程池  防止线程过多，5就够用了
//            ExecutorService executorService = Executors.newFixedThreadPool(5);
            //4条数据，分成4个线程来查询
            ExecutorService executorService = Executors.newFixedThreadPool(cishu);
            //Future用于获取结果
            List<Future<List>> futures=executorService.invokeAll(tasks);
            //处理线程返回结果
            if(futures!=null&&futures.size() > 0){
                for (Future<List> future:futures){
                    list.addAll(future.get());
                }
            }
            //关闭线程池，一定不能忘记
            executorService.shutdown();
        }catch (Exception e){
            e.printStackTrace();
        }


        return list;
    }

    // 批量新增
    private void batchAdd(){

        // 新增条数
        int number = 5000000;

        List<TeacherTable> teacherTables = new ArrayList<>();
        for (int i = 0; i <= number; i++) {
            TeacherTable node = new TeacherTable();
            node.setTeacherName(i+"张老师");
            node.setTeacherNo(i + "");
            node.setCreateTime(new Date());
            node.setTeacherAddress(i+"号地址");
            teacherTables.add(node);


            int total = 1000000; // 每多少条插入一次,测试100万

            if (teacherTables.size() % total == 0) {
//                List<TeacherTable> finalTeacherTables = teacherTables;
                executorAdd(teacherTables);
                teacherTables = new ArrayList<>();
            }

        }
    }

    // 集合切割为 5000条执行一次
    private void executorAdd(List<TeacherTable> finalTeacherTables){
        List<List<TeacherTable>> lists = ColltionUtils.splitList(finalTeacherTables, 5000);
        for (List<TeacherTable> listList : lists) {
            ThreadPoolUtils.dataMigrateExecutor.execute(() -> {
                    saveBatch(listList);
            });
        }

    }




}
